/**
 * Copyright (c) [2025] [何屹林]
 *
 * 保留所有权利。
 *
 * 文件名称：mainwindow.cpp
 * 模块功能说明：
 * 该模块实现展示功能，主要承载ui，实例化了逻辑处理对象，调用逻辑处理对象的各个接口
 *
 * 华南师范大学-计算机学院-网络工程-1班
 * 作者：何屹林-20222132023
 * 完成日期：2025年7月24日
 */
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("ComplierVisual");

//    connect(ui->textEdit,QInternal::RelayoutDropped,this,&MainWindow::on_textEdit1_dropEvent);
    connect(ui->actionOpenReg,&QAction::triggered,this,&MainWindow::openReg);
    connect(ui->actionOpenGram,&QAction::triggered,this,&MainWindow::openGram);
    connect(ui->actionSave,&QAction::triggered,this,&MainWindow::save);
    connect(ui->actionSaveAs,&QAction::triggered,this,&MainWindow::saveAs);
    connect(ui->actionClear,&QAction::triggered,this,&MainWindow::clear);
    connect(ui->actionExit,&QAction::triggered,this,&MainWindow::exit);
    connect(ui->actionHelp,&QAction::triggered,this,&MainWindow::help);

    connect(ui->actionNFA,&QAction::triggered,this,&MainWindow::NFAMakerShow);
    connect(ui->actionDFA,&QAction::triggered,this,&MainWindow::DFAMakerShow);
    connect(ui->actionminDFA,&QAction::triggered,this,&MainWindow::minDFAMakerShow);
    connect(ui->actionCode,&QAction::triggered,this,&MainWindow::genCodeShow);
    connect(ui->actionFirst_Follow,&QAction::triggered,this,&MainWindow::FirstFollowShow);
    connect(ui->actionLR_0_DFA,&QAction::triggered,this,&MainWindow::LR_0_DFAShow);
    connect(ui->actionSLR1,&QAction::triggered,this,&MainWindow::SLRShow);
    connect(ui->actionLR_1_DFA,&QAction::triggered,this,&MainWindow::LR_1_DFAShow);
    connect(ui->actionLR_1,&QAction::triggered,this,&MainWindow::LR_1_TableShow);
    connect(ui->actionLR_1_process,&QAction::triggered,this,&MainWindow::LR_1_ProcessShow);
    connect(ui->actionAST,&QAction::triggered,this,&MainWindow::ASTShow);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::openReg()
{
    regFileAddress=QFileDialog::getOpenFileName();
    if (regFileAddress.isEmpty()) return;
    int t=regFileAddress.length()-1;
    while(regFileAddress[t]!='/') t--;
    regFilePath=regFileAddress.mid(0,t);
    regFileName=regFileAddress.mid(t+1);
    setWindowTitle(regFileName);

    file_read(regFileAddress);
}

void MainWindow::openGram()
{
    gramFileAddress=QFileDialog::getOpenFileName();
    if (gramFileAddress.isEmpty()) return;
    int t=gramFileAddress.length()-1;
    while(gramFileAddress[t]!='/') t--;
    gramFilePath=gramFileAddress.mid(0,t);
    gramFileName=gramFileAddress.mid(t+1);
    setWindowTitle(gramFileName);

    file_read(gramFileAddress);
}


void MainWindow::save()
{
    if(regFileAddress.isEmpty()||gramFileAddress.isEmpty())
    {
        saveAs();
        return;
    }

    QFile regFile(regFileAddress);
    if(regFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&regFile);
        QString text = ui->textEdit->toPlainText();
        out<<text;
        regFile.close();
    }
    else
    {
        QMessageBox::information(this,"警告！","无法保存正则表达式文件："+regFile.errorString());
        return;
    }

    QFile gramFile(gramFileAddress);
    if(gramFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&gramFile);
        QString text = ui->textEdit_2->toPlainText();
        out<<text;
        gramFile.close();
    }
    else
    {
        QMessageBox::information(this,"警告！","无法保存文法文件："+gramFile.errorString());
        return;
    }
}

void MainWindow::saveAs()
{
    QString regPath = regFilePath+"/output/正则文件.txt";
    QString gramPath = regFilePath+"/output/文法文件.txt";
    QString regFilename = QFileDialog::getSaveFileName(this, tr("Save As"), regPath, tr("文本文件 (*.txt)"));
    QString gramFilename = QFileDialog::getSaveFileName(this, tr("Save As"), gramPath, tr("文本文件 (*.txt)"));
    if(!regFilename.isNull())
    {
        regFileAddress=regFilename;
        int t=regFileAddress.length()-1;
        while(regFileAddress[t]!='/') t--;
        regFileName=regFileAddress.mid(t+1);
        setWindowTitle(regFileName);
    }
    else
        return;

    QFile regFile(regFileAddress);
    if(regFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&regFile);
        QString text = ui->textEdit->toPlainText();
        out<<text;
        regFile.close();
    }
    else
    {
        QMessageBox::information(this,"警告！","无法保存文件："+regFile.errorString());
        return;
    }

    if(!gramFilename.isNull())
    {
        gramFileAddress=gramFilename;
        int t=gramFileAddress.length()-1;
        while(gramFileAddress[t]!='/') t--;
        gramFileName=gramFileAddress.mid(t+1);
        setWindowTitle(gramFileName);
    }
    else
        return;

    QFile gramFile(gramFileAddress);
    if(gramFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&gramFile);
        QString text = ui->textEdit_2->toPlainText();
        out<<text;
        gramFile.close();
    }
    else
    {
        QMessageBox::information(this,"警告！","无法保存文件："+gramFile.errorString());
        return;
    }
}

void MainWindow::clear()
{
    ui->textEdit->setText("");
    ui->textEdit_2->setText("");
    Lr1ProcessShowModel->clear();
    setWindowTitle("ComplierVisual");
    logic.clear();
}

void MainWindow::exit()
{
    QCoreApplication::quit();
}

void MainWindow::help()
{
    QMessageBox::information(NULL, "帮助", "将对应语言的正则表达式和文法打开，目前只支持输入文法框，程序能够自动分析工作区的代码。\n请将代码放入input.txt文件中\n\n正则表达式格式要求："
                                     "1.无需生成DFA图的，无需添加前缀，存在_前缀的才需要生成DFA图\n"
                                     "2.对于有实义的大类编码，需要加上_前缀\n"
                                     "3.对于无实义的大类编码，需要加上_！前缀\n"
                                     "4.对于子类编码，需要加上__前缀\n"
                                           "例如：digit=[0-9] 或_num100=digit+（100为编号）"
                                     "\n\n文法格式要求：\n1、左侧非终结符只能出现单个词，非终结符后需要有空格以及 -> 符号；\n2、不可包含死递归文法\n例如： E -> E e|e", QMessageBox::Yes, QMessageBox::Yes);
    return;
}

void MainWindow::file_read(QString fileName)
{
    if(!fileName.isEmpty())
    {
        QFile file(fileName);
        if(file.open(QIODevice::ReadOnly| QIODevice::Text))
        {
            setWindowTitle(fileName);
            QTextStream in(&file);
            QString content=in.readAll();
            if(fileName==regFileAddress)
            {
                logic.getContent(content);
                ui->textEdit->setText(content);
                logic.beginWork();
            }
            else if(fileName == gramFileAddress)
                ui->textEdit_2->setText(content);
            file.close();
        }
        else
        {
            QMessageBox::information(this,"警告！","打不开文件："+file.errorString());
            return;
        }
    }
    return;
}

//void MainWindow::dragEnterEvent(QDragEnterEvent *event)
//{
//    QPoint pos = mapFromGlobal(event->position().toPoint());
//    QObject* child = childAt(pos);

//    if (qobject_cast<QTextEdit*>(child)) {
//        if (event->mimeData()->hasUrls()) {
//            event->acceptProposedAction();
//            return;
//        }
//    }
//    event->ignore();

//}

//void MainWindow::dropEvent(QDropEvent *event)
//{
//    QPoint pos = mapFromGlobal(event->position().toPoint());
//    QObject* target = childAt(pos);

//    if (QTextEdit* textEdit = qobject_cast<QTextEdit*>(target)) {
//        if (textEdit == ui->textEdit) {
//            handleDropEvent(event, textEdit, regFileAddress, regFileName);
//        }
//        else if (textEdit == ui->textEdit_2) {
//            handleDropEvent(event, textEdit, gramFileAddress, gramFileName);
//        }
//    }
//}

//void MainWindow::handleDropEvent(QDropEvent *event, QTextEdit* textEdit, QString &filePath, QString &fileName)
//{
//    const QMimeData* mimeData = event->mimeData();
//    if (mimeData->hasUrls()) {
//        QList<QUrl> urlList = mimeData->urls();
//        filePath = urlList.first().toLocalFile();

//        // 提取文件名
//        QFileInfo fileInfo(filePath);
//        fileName = fileInfo.fileName();

//        // 更新UI显示
//        textEdit->setText(fileName);

//        // 清除可能存在的占位文本
//        textEdit->setPlaceholderText("");

//        // 处理文件
//        if (textEdit == ui->textEdit) {
//            qDebug() << "处理注册文件:" << filePath;
//                file_read(filePath); // 注册文件处理
//        } else {
//            qDebug() << "处理语法文件:" << filePath;
//                file_read(filePath); // 语法文件处理
//        }

//        event->acceptProposedAction();
//    }
//}

//void MainWindow::on_textEdit_dragEnterEvent(QDragEnterEvent* event)
//{
//    if (event->mimeData()->hasUrls())
//        event->acceptProposedAction();
//    else
//        event->ignore();
//}

//void MainWindow::on_textEdit_dropEvent(QDropEvent* event)
//{
//    const QMimeData* mimeData = event->mimeData();
//    if (mimeData->hasUrls()) {
//        QList<QUrl> urlList = mimeData->urls();
//        regFileAddress = urlList.first().toLocalFile();

//        // 提取文件名并更新UI
//        int pos = regFileAddress.lastIndexOf('/');
//        regFileName = (pos >= 0) ? regFileAddress.mid(pos + 1) : regFileAddress;
//        ui->textEdit->setText(regFileName);

//        // 处理文件
//        file_read(regFileAddress);
//    }
//}

//void MainWindow::on_textEdit_2_dragEnterEvent(QDragEnterEvent* event)
//{
//    if (event->mimeData()->hasUrls())
//        event->acceptProposedAction();
//    else
//        event->ignore();
//}

//void MainWindow::on_textEdit_2_dropEvent(QDropEvent* event)
//{
//    const QMimeData* mimeData = event->mimeData();
//    if (mimeData->hasUrls()) {
//        QList<QUrl> urlList = mimeData->urls();
//        gramFileAddress = urlList.first().toLocalFile();

//        // 提取文件名并更新UI
//        int pos = gramFileAddress.lastIndexOf('/');
//        gramFileName = (pos >= 0) ? gramFileAddress.mid(pos + 1) : gramFileAddress;
//        ui->textEdit_2->setText(gramFileName);

//        // 处理文件
//        file_read(gramFileAddress);
//    }
//}

void MainWindow::FirstFollowShow()
{
    if(!logic.analysis(ui->textEdit_2->toPlainText()))
        QMessageBox::warning(this, "提示", "文法分析失败，请检查文法格式是否符合要求", QMessageBox::Yes);


    QString title="first集合与follow集合：";
    QStringList header;
    header.append("first");
    header.append("follow");


    logic.firstFollowShow(title,header);
    return;
}

void MainWindow::LR_0_DFAShow()
{

    if(!logic.analysis(ui->textEdit_2->toPlainText()))
        QMessageBox::warning(this, "提示", "文法分析失败，请检查文法格式是否符合要求", QMessageBox::Yes);
    logic.extend();//扩充语法

    QString title="LR(0)对应的DFA图";

    logic.lr0_DfaShow(title);
    return;
}

void MainWindow::SLRShow()
{
    if(!logic.analysis(ui->textEdit_2->toPlainText()))
        QMessageBox::warning(this, "提示", "文法分析失败，请检查文法格式是否符合要求", QMessageBox::Yes);
    logic.extend();//扩充语法

    if(logic.isSLR1())
        QMessageBox::warning(this, "提示", "该文法是SLR(1)文法！", QMessageBox::Yes);
    else
        QMessageBox::warning(this, "提示", "该文法不是SLR(1)文法！\n"+logic.getSLR1Warning(), QMessageBox::Yes);
    return;
}

void MainWindow::LR_1_DFAShow()
{
    if(!logic.analysis(ui->textEdit_2->toPlainText()))
        QMessageBox::warning(this, "提示", "文法分析失败，请检查文法格式是否符合要求", QMessageBox::Yes);
    logic.extend();//扩充语法

    QString title="LR(1)对应的DFA图";

    logic.lr1_DfaShow(title);
    return;
}

void MainWindow::LR_1_TableShow()
{
    if(!logic.analysis(ui->textEdit_2->toPlainText()))
        QMessageBox::warning(this, "提示", "文法分析失败，请检查文法格式是否符合要求", QMessageBox::Yes);
    logic.extend();//扩充语法

    QString title="LR(1)分析表";

    logic.lr1_TableShow(title);
    return;
}

void MainWindow::LR_1_ProcessShow()
{
    if (logic.isLr1TableEmpty()) { //缺少LR1分析表
        QMessageBox::warning(this, "提示", "分析失败，缺少LR1分析表", QMessageBox::Yes);
        return;
    }

    if(!logic.loadLex(gramFilePath)){
        QMessageBox::warning(this, "提示", "找不到对应的lex文件！", QMessageBox::Yes);
        return;
    }

    QVector<QVector<QString>> Lr1ProcessTable=logic.lr1_ProcessShow();
    tableViewProcessShow(Lr1ProcessTable);
    return;
}

void MainWindow::ASTShow()
{
    if (logic.isLexEmpty()) { //缺少必要元素
        QMessageBox::warning(this, "提示", "分析失败，未进行源程序分析", QMessageBox::Yes);
        return;
    }

    ui->treeView->setModel(logic.genTreeModel(this));
    ui->treeView->header()->hide();
    ui->treeView->expandAll();

    ui->graphicsView->setScene(logic.genTreeGraph(this, 600));
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);
}

void MainWindow::tableViewProcessShow(QVector<QVector<QString>> contentTable)
{
    QStringList header,colHeader;
    header.append("分析栈");
    header.append("输入");
    header.append("动作");
    for(int i=0;i<contentTable.size();i++) colHeader.append(QString::number(i));

    Lr1ProcessShowModel = new QStandardItemModel (colHeader.size(), header.size());

    Lr1ProcessShowModel->setHorizontalHeaderLabels(header);
    Lr1ProcessShowModel->setVerticalHeaderLabels(colHeader);

    for(int i=0;i<contentTable.size();i++)
        for(int j=0;j<contentTable[i].size();j++)
            Lr1ProcessShowModel->setItem(i,j,new QStandardItem(contentTable[i][j]));

    ui->tableView->setModel(Lr1ProcessShowModel);
    ui->tableView->resizeColumnToContents(0);
    ui->tableView->resizeColumnToContents(1);
    ui->tableView->resizeColumnToContents(2);
    return;
}

void MainWindow::NFAMakerShow()
{
    if (logic.isNFATableEmpty()) { //缺少必要元素
        QMessageBox::warning(this, "提示", "展示失败，缺少NFA表", QMessageBox::Yes);
        return;
    }

    logic.getContent(ui->textEdit->toPlainText());

    QString title="NFA表";


    logic.NFATableShow(title);
    return;
}

void MainWindow::DFAMakerShow()
{
    if (logic.isDFATableEmpty()) { //缺少必要元素
        QMessageBox::warning(this, "提示", "展示失败，缺少DFA表", QMessageBox::Yes);
        return;
    }


    logic.getContent(ui->textEdit->toPlainText());

    QString title="DFA表";


    logic.DFATableShow(title);
    return;
}

void MainWindow::minDFAMakerShow()
{

    logic.getContent(ui->textEdit->toPlainText());

    if (logic.isMiniDFATableEmpty()) { //缺少必要元素
        QMessageBox::warning(this, "提示", "展示失败，缺少miniDFA表", QMessageBox::Yes);
        return;
    }

    QString title="miniDFA表";

    logic.MiniDFATableShow(title);
    return;
}

void MainWindow::genCodeShow()
{
    logic.getContent(ui->textEdit->toPlainText());
    if (logic.isLexCodeEmpty()) { //缺少必要元素
        QMessageBox::warning(this, "提示", "产生失败，出现未知错误", QMessageBox::Yes);
        return;
    }

    QDir dir(regFilePath+"/output");

    if (!dir.exists())
    {
        dir.mkdir(regFilePath+"/output");
    }

    QString codePath = regFilePath+"/output/code.cpp";
    QString lexFilename = QFileDialog::getSaveFileName(this, tr("Save As"), codePath, tr("c++源程序 (*.cpp)"));
    QStringList arguments = {regFilePath+"/input.txt",  regFilePath+"/output/sample.lex"};


    QFile lexFile(codePath);
    if(lexFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&lexFile);
        QString text = logic.getLexCode();
        out<<text;
        lexFile.close();
        QDesktopServices::openUrl(QUrl("file:///"+codePath));
    }
    else
    {
        QMessageBox::information(this,"警告！","无法生成文件："+lexFile.errorString());
        return;
    }

    if(!logic.compileAndRunCode(codePath,arguments))
        QMessageBox::information(this,"警告！","无法编译文件！");
    else{
        QMessageBox::information(this,"提示","编译成功！",QMessageBox::Yes);
        QDesktopServices::openUrl(QUrl("file:///"+regFilePath+"/output/sample.lex"));
    }


    return;
}

